package com.egdigital.allzic.data.json;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import android.content.Context;

import com.egdigital.allzic.data.object.Category;
import com.egdigital.allzic.data.object.Station;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class JsonCacheManager {

	private static final String	TAG					= JsonCacheManager.class.getSimpleName();	// log
	public static final String	INTENT_RECENT		= "recent";
	public static final String	INTENT_FAVORITE		= "favorite";
	public static final String	INTENT_CATEGORY		= "category";
	//
	public static final String	FAVORITE_CATEGORY	= "cat.json";
	public static final String	FAVORITE_STATION	= "sta.json";
	public static final String	RECENT_STATION		= "rec.json";

	/**
	 * Get all categories from the Json file
	 * 
	 * @param context
	 *        the application context
	 * @return List of category in the file. Null if empty
	 */
	public static List<Category> getCategories(Context context) {
		JsonParser jsonParser = new JsonParser();
		JsonObject jsonObject;
		try {
			jsonObject = (JsonObject) jsonParser.parse(getRawJsonContent(context, FAVORITE_CATEGORY));
		} catch (Exception e) {
			return new ArrayList<Category>();
		}
		List<Category> categories = new ArrayList<Category>();
		JsonArray categoryArray = (JsonArray) jsonObject.get("Category");
		if (categoryArray != null) {
			for (int i = 0; i < categoryArray.size(); i++) {
				int id = categoryArray.get(i).getAsJsonObject().get("id").getAsInt();
				String title = categoryArray.get(i).getAsJsonObject().get("title").getAsString();
				categories.add(new Category(id, title));
			}
		}
		return categories;
	}

	/**
	 * Return stations in the favorite file
	 * 
	 * @param context
	 *        the application context
	 * @param mode
	 *        It is the file name (recent or favorite)
	 * @return List of station in the file. Null if empty
	 */
	public static List<Station> getStations(Context context, String mode) {
		JsonParser jsonParser = new JsonParser();
		JsonObject jsonObject;
		try {
			jsonObject = (JsonObject) jsonParser.parse(getRawJsonContent(context, mode));
		} catch (Exception e) {
			return new ArrayList<Station>();
		}
		List<Station> stations = new ArrayList<Station>();
		JsonArray radioArray = (JsonArray) jsonObject.get("Radio");
		for (int i = 0; i < radioArray.size(); i++) {
			int id = radioArray.get(i).getAsJsonObject().get("id").getAsInt();
			String title = radioArray.get(i).getAsJsonObject().get("title").getAsString();
			String subtitle = radioArray.get(i).getAsJsonObject().get("subtitle").getAsString();
			String genre = radioArray.get(i).getAsJsonObject().get("genre").getAsString();
			int hq = radioArray.get(i).getAsJsonObject().get("hq").getAsInt();
			String category = radioArray.get(i).getAsJsonObject().get("category").getAsString();
			String thumb = radioArray.get(i).getAsJsonObject().get("thumb").getAsString();
			String thumbSmartphone = radioArray.get(i).getAsJsonObject().get("thumb_smartphone").getAsString();
			String background = radioArray.get(i).getAsJsonObject().get("background").getAsString();
			String url = radioArray.get(i).getAsJsonObject().get("url").getAsString();
			String aac = radioArray.get(i).getAsJsonObject().get("aac").getAsString();
			String mp3 = radioArray.get(i).getAsJsonObject().get("mp3").getAsString();
			String playlist = radioArray.get(i).getAsJsonObject().get("playlist").getAsString();
			int hits = radioArray.get(i).getAsJsonObject().get("hits").getAsInt();
			JsonArray categoriesArray = radioArray.get(i).getAsJsonObject().get("categories").getAsJsonArray();
			List<Integer> categories = new ArrayList<Integer>();
			for (int j = 0; j < categoriesArray.size(); j++) {
				categories.add(categoriesArray.get(j).getAsJsonObject().get("id").getAsInt());
			}
			String date = radioArray.get(i).getAsJsonObject().get("date").getAsString();
			stations.add(new Station(id, title, subtitle, genre, hq, category, thumb, thumbSmartphone, background, url, aac, mp3, playlist, hits, categories, date));
		}
		return stations;
	}

	/**
	 * Read the Json File stored on the application's asset folder
	 * 
	 * @param fileName
	 *        Name of the file stored in the asset
	 * @param context
	 *        Application's context
	 * @return Raw file's content in String format
	 * @throws IOException
	 */
	private static String getRawJsonContent(Context context, String fileName) throws IOException {
		/*
		 * AssetManager manager = mContext.getAssets(); InputStream file = manager.open(fileName);
		 */
		FileInputStream file = new FileInputStream(new File(context.getCacheDir(), fileName));
		byte[] data = new byte[file.available()];
		file.read(data);
		file.close();
		return new String(data);
	}

	/**
	 * Read the Json File stored on the application's asset folder
	 * 
	 * @param context
	 *        Application's context
	 * @param fileName
	 *        Name of the file stored in the asset
	 * @return Raw file's content in String format
	 * @throws IOException
	 */
	private static void setRawJsonContent(Context context, String fileName, JsonObject jsonContent) throws IOException {
		FileOutputStream file = new FileOutputStream(new File(context.getCacheDir(), fileName));
		OutputStreamWriter writer = new OutputStreamWriter(file);
		writer.append(jsonContent.toString());
		writer.close();
		file.close();
	}

	/**
	 * Save categories in the favorite file
	 * 
	 * @param context
	 *        Application's context
	 * @param categories
	 *        List of category to save
	 * @throws IOException
	 */
	public static void setCategories(Context context, List<Category> categories) throws IOException {
		JsonObject rootObject = new JsonObject();
		JsonArray categoryArray = new JsonArray();
		for (Category category : categories) {
			JsonObject object = new JsonObject();
			object.addProperty("id", category.getId());
			object.addProperty("title", category.getTitle());
			categoryArray.add(object);
		}
		rootObject.add("Category", categoryArray);
		setRawJsonContent(context, FAVORITE_CATEGORY, rootObject);
	}

	/**
	 * Save stations in the favorite file
	 * 
	 * @param context
	 *        Application's context
	 * @param stations
	 *        List of station to save
	 * @throws IOException
	 */
	public static void setStations(Context context, List<Station> stations, String mode) throws IOException {
		JsonObject rootObject = new JsonObject();
		JsonArray stationArray = new JsonArray();
		for (Station station : stations) {
			JsonObject object = new JsonObject();
			object.addProperty("id", station.getmId());
			object.addProperty("title", station.getmTitle());
			object.addProperty("subtitle", station.getmSubtitle());
			object.addProperty("genre", station.getmGenre());
			object.addProperty("hq", station.getmHq());
			object.addProperty("category", station.getmCategory());
			object.addProperty("thumb", station.getmThumb());
			object.addProperty("thumb_smartphone", station.getmThumbMobile());
			object.addProperty("background", station.getmBackground());
			object.addProperty("url", station.getmUrl());
			object.addProperty("aac", station.getmFlux_aac());
			object.addProperty("mp3", station.getmFlux_mp3());
			object.addProperty("playlist", station.getmPlaylist());
			object.addProperty("hits", station.getmHits());
			JsonArray categoriesArray = new JsonArray();
			if (station.getmListCategory() != null) {
				for (int cat : station.getmListCategory()) {
					JsonObject categoryObject = new JsonObject();
					categoryObject.addProperty("id", cat);
					categoriesArray.add(categoryObject);
				}
			}
			object.add("categories", categoriesArray);
			object.addProperty("date", station.getmDate());
			stationArray.add(object);
		}
		rootObject.add("Radio", stationArray);
		setRawJsonContent(context, mode, rootObject);
	}

	/**
	 * Delete the favorite station file
	 * 
	 * @param context
	 *        Application's context
	 * @return true if the station category file was deleted, false otherwise.
	 */
	public static boolean ClearCache(Context context, String mode) {
		return new File(context.getCacheDir(), mode).delete();
	}

	/**
	 * Add a new category in favorite file
	 * 
	 * @param context
	 *        Application's context
	 * @param category
	 *        Category to store in the favorite file
	 * @throws IOException
	 */
	public static void addCategory(Context context, Category category) throws IOException {
		List<Category> categories = new CopyOnWriteArrayList<Category>(getCategories(context));
		categories.add(category);
		setCategories(context, categories);
	}

	/**
	 * Add a new station in favorite file
	 * 
	 * @param context
	 *        Application's context
	 * @param station
	 *        Station to store in the favorite file
	 * @throws IOException
	 */
	public static void addStation(Context context, Station station, String mode) throws IOException {
		List<Station> stations = new CopyOnWriteArrayList<Station>(getStations(context, mode));
		stations.add(station);
		setStations(context, stations, mode);
	}

	/**
	 * Remove the category at the given position
	 * 
	 * @param context
	 *        Application's context
	 * @param position
	 *        Position of the soon-to-be-deleted category
	 * @throws IOException
	 */
	public static List<Category> removeCategory(Context context, int position) throws IOException {
		List<Category> categories = new CopyOnWriteArrayList<Category>(getCategories(context));
		if (categories.size() >= position) {
			categories.remove(position);
			setCategories(context, categories);
		}
		return categories;
	}

	/**
	 * Remove the given category
	 * 
	 * @param context
	 *        Application's context
	 * @param category
	 *        Category to remove
	 * @throws IOException
	 */
	public static void removeCategory(Context context, Category category) throws IOException {
		List<Category> categories = new CopyOnWriteArrayList<Category>(getCategories(context));
		for (Category cat : categories) {
			if (cat.getId() == category.getId())
				categories.remove(cat);
		}
		setCategories(context, categories);
	}

	/**
	 * Remove the station at the given position
	 * 
	 * @param context
	 *        Application's context
	 * @param position
	 *        Position of the soon-to-be-deleted station
	 * @throws IOException
	 */
	public static List<Station> removeStation(Context context, int position, String mode) throws IOException {
		List<Station> stations = new CopyOnWriteArrayList<Station>(getStations(context, FAVORITE_STATION));
		if (stations.size() >= position) {
			stations.remove(position);
			setStations(context, stations, mode);
		}
		return stations;
	}

	/**
	 * Remove the given station
	 * 
	 * @param context
	 *        Application's context
	 * @param station
	 *        Station to remove
	 * @throws IOException
	 */
	public static void removeStation(Context context, Station station, String mode) throws IOException {
		List<Station> stations = new CopyOnWriteArrayList<Station>(getStations(context, mode));
		for (Station sta : stations) {
			if (sta.getmId() == station.getmId())
				stations.remove(sta);
		}
		setStations(context, stations, mode);
	}

	/**
	 * @param station
	 * @param context
	 * @param mode
	 *        It is the file name (recent or favorite)
	 * @return <code>true</code> if already in file, else <code>false</code>
	 */
	public static boolean isStationSaved(Station station, Context context, String mode) {
		List<Station> stations = getStations(context, mode);
		if (stations != null) {
			for (Station sta : stations) {
				if (sta.getmId() == station.getmId())
					return true;
			}
		}
		return false;
	}

	/**
	 * Check if Category is already favorite
	 * 
	 * @param category
	 *        an object {@link Category}
	 * @param context
	 *        the application context
	 * @return true if the Category is already in the file, else false
	 */
	public static boolean isCategoryFavorite(Category category, Context context) {
		List<Category> categories = getCategories(context);
		if (categories != null) {
			for (Category cat : categories) {
				if (cat.getId() == category.getId())
					return true;
			}
		}
		return false;
	}
}
